home *** CD-ROM | disk | FTP | other *** search
/ The Programmer Disk / The Programmer Disk (Microforum).iso / xpro / c3 / pro24 / phase1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-08-07  |  33.2 KB  |  1,135 lines

  1. /* phase1.c -- Phase 1 of adagio compilation...     */ 
  2. /*
  3.  * this module parses adagio programs and builds a linked list structure
  4.  * consisting of notes and control changes in time order.
  5.  */
  6.  
  7. /*****************************************************************************
  8. *        Change Log
  9. *  Date        | Change
  10. *-----------+-----------------------------------------------------------------
  11. * 31-Dec-85 | Created changelog
  12. * 31-Dec-85 | Add c:\ to include directives
  13. * 31-Dec-85 | Added standard command scanner, metronome variable, need to add 
  14. *        | cmdline_help procedure
  15. * 31-Dec-85 | Call intr_init
  16. * 31-Dec-85 | Set musictrace from command line via -trace
  17. * 31-Dec-85 | Added -poll
  18. *  1-Jan-86 | Put error messages out to stderr
  19. *  1-Jan-86 | Set IsAT.     Can be later overridden by -at and -xt switches,
  20. *        | currently only used for diagnostics (may be needed for
  21. *        | compatibles, who knows?  In which case remove the tests which
  22. *        | confirm the type of processor)
  23. *  1-Jan-86 | <rgd/jmn> Removed dur-adjusted message
  24. *  1-Jan-86 | Added miditrace
  25. * 18-Jan-86 | Shortened durations by 1/200 s to avoid roundoff problems --
  26. *        | see buildnote for details.
  27. *  3-Mar-86 | Allow octave and accidentals in either order after pitch name.
  28. *        | Default octave is now one that gets nearest previous pitch,
  29. *        |  the tritone (half an octave) interval is descending by default.
  30. *        | Special commands handled by table search, !Rate command added
  31. *        |  to scale all times by a percentage (50 = half speed).
  32. *  9-Mar-86 | Use space to limit amount of storage allocation.    Otherwise
  33. *        |    exhausting storage in phase1 caused phase2 to fail.
  34. * 12-Mar-86 | Broke off command line parser into adagio.c, only parser remains
  35. * 24-Mar-86 | Changed representation from note_struct to event_struct
  36. *        | Parse M, N, O, X, and Y as control change commands
  37. * 23-May-86 | Added , and ; syntax: "," means "N0\n", ";" means "\n"
  38. * 16-Jul-86 | modify to only call toupper/lower with upper/lower case as
  39. *        |  parameter to be compatible with standard C functions
  40. *  7-Aug-86 | fixed bug with default pitches and rests
  41. *****************************************************************************/
  42.  
  43. #include "cext.h"
  44. #include "stdio.h"
  45. #include "adagio.h"
  46. #include "cmdline.h"
  47. #include "phase1.h"
  48.  
  49. extern long space;    /* remaining free bytes */
  50.  
  51. /****************************************************************************
  52. * The following are used to simulate fixed point with the radix point
  53. * 8 bits from the right:
  54. ****************************************************************************/
  55. #define unity 256
  56. #define round(x) (((x)+128)>>8)
  57. #define precise(x) ((x)<<8)
  58.  
  59. #define nullstring(s) (s[0] == NULL)
  60.  
  61. /****************************************************************************
  62. * Routines local to this module:
  63. ****************************************************************************/
  64. private         event_type ctrlalloc();
  65. private           void    do_a_rest();
  66. private           void    doabsdur();
  67. private           void    doabspitch();
  68. private           void    docomment();
  69. private           void    doctrl();
  70. private           void    dodur();
  71. private           void    doerror();
  72. private           void    doloud();
  73. private           void    donextdur();
  74. private           void    dopitch();
  75. private           void    doprogram();
  76. private           void    dorate();
  77. private           void    dospecial();
  78. private           void    dotempo();
  79. private           void    dotime();
  80. private           void    dovoice();
  81. private           void    fferror();
  82. private        boolean init();
  83. private           void    ins_event();
  84. private        boolean ins_ctrl();
  85. private        boolean ins_note();
  86. private            int issymbol();
  87. private           void    marker();
  88. private         event_type nalloc();
  89. private           void    parseend();
  90. private           void    parsefield();
  91. private        boolean parsenote();
  92. private           void    reverse();
  93. private            int scan();
  94. private            int scan1();
  95. private            int scanint();
  96.  
  97. /****************************************************************************
  98. * data structures for parser lookup tables
  99. ****************************************************************************/
  100.  
  101. struct durt {    /* duration translation table */
  102.     char symbol;
  103.     long value;
  104. };
  105. struct durt durtable[5] = {
  106.     'W', 240,
  107.     'H', 120,
  108.     'Q', 60,
  109.     'I', 30,
  110.     'S', 15
  111. };
  112.  
  113. struct loudt {    /* loudness translation table */
  114.     char symbol[4];
  115.     int value;
  116. };
  117.  
  118. struct loudt loudtable[] = {
  119.     "PPP", 20,
  120.     "PP\0", 26,
  121.     "P\0\0", 34,
  122.     "MP\0", 44,
  123.     "MF\0", 58,
  124.     "F\0\0", 75,
  125.     "FF\0", 98,
  126.     "FFF", 127
  127. };
  128.  
  129. private char *ssymbols[] = {{"TEMPO"}, {"RATE"}};
  130.             /* this was inside istempo, but */
  131.             /* I moved it here because of a compiler bug */
  132.  
  133. #define sym_tempo 0
  134. #define sym_rate 1
  135. /* number of symbols */
  136. #define sym_n 2
  137.  
  138. #define linesize 100
  139. private char line[linesize];    /* the input line */
  140. private char token[linesize];    /* a token scanned from the input line */
  141.  
  142. private boolean pitch_flag;    /* set when a pitch is indicated */
  143.     /* (if controls changes are given, only allocate a note event if
  144.      *  a pitch was specified -- i.e. when pitch_flag is set)
  145.      */
  146. private boolean rest_flag;    /* set when a rest (R) is found */
  147.     /* this flag is NOT inherited by the next line */
  148.  
  149. private boolean symbolic_dur_flag;
  150.         /* true if last dur was not absolute
  151.          * (if this is set, then the default duration is changed
  152.          *  accordingly when the tempo is changed.)
  153.          */
  154.  
  155. private boolean ctrlflag[nctrl];
  156.         /* true if control change was present
  157.          * ctrlflag[0] true if ANY control change
  158.          * was present
  159.          */
  160. private int ctrlval[nctrl];
  161.         /* the new value of the control */
  162.  
  163. private int last_prog;    /* saved value of program from previous line */
  164.     /* (this is needed to implement the rule that note
  165.      *  events are generated for rests if the program has changed.)
  166.      */
  167.  
  168. /****************************************************************************
  169. *                state variables
  170. * Because each line of an Adagio score inherits properties from the previous
  171. * line, it makes sense to implement the parser as a collection of routines
  172. * that make small changes to some global state.     For example, pitch is a
  173. * global variable.  When the field G4 is encountered, the dopitch routine
  174. * assigns the pitch number for G4 to the variable pitch.  After all fields
  175. * are processed, these variables describe the current note and contain the
  176. * default parameters for the next note as well.
  177. *
  178. * Global variables that are used in this way by the parsing rountines are:
  179. ****************************************************************************/
  180. private int
  181.     linex,    /* index of the next character to be scanned */
  182.     lineno,    /* current line number */
  183.     fieldx,    /* index of the current character within a field */
  184.     pitch,    /* pitch of note */
  185.     loud,    /* loudness of note */
  186.     voice,    /* voice (midi channel) of note */
  187.     program;    /* midi program (timbre control) of note */
  188.  
  189. private boolean ndurp;        /* set when a next (N) is indicated */
  190.     /* (next time defaults to the current time plus duration unless
  191.      *  overridden by a next (N) command whose presence is signalled
  192.      *  by ndurp.)
  193.      */
  194.  
  195. private long
  196.     thetime,    /* the starting time of the note */
  197.     rate,    /* time rate -- scales time and duration, default = 100 */
  198.     ntime,    /* the starting time of the next note */
  199.     dur,    /* the duration of the note */
  200.     tempo,    /* the current tempo */
  201.     start;    /* the reference time (time of last !tempo or !rate cmd) */
  202.  
  203. private int pitchtable[7] = { 57, 59, 48, 50, 52, 53, 55 };
  204.  
  205. extern char score_na[name_length];
  206.  
  207. private int note_count = 0;    /* the number of notes translated */
  208. private int ctrl_count = 0;    /* ditto for control commands */
  209.  
  210. private int debug = false;    /* controls verbose printout */
  211.  
  212. /****************************************************************************
  213. *                ctrlalloc
  214. * Outputs: returns an event_type for representing a control change
  215. *       returns NULL if space is unavailable
  216. * Effect: allocates ctrlsize bytes
  217. * Assumes: space tells how many bytes are available
  218. ****************************************************************************/
  219. private event_type ctrlalloc()
  220. {    
  221.     char *getmem();
  222.     event_type result;
  223.     space -= ctrlsize;
  224.     if (space > 0) {
  225.     result = (event_type ) getmem(ctrlsize);
  226.     if (result == NULL)    /* this should never happen ... */
  227.         printf("Internal error: Out of memory, space = %ld.\n",space);
  228.     } else result = NULL;
  229.     return result;
  230. }
  231.  
  232. /****************************************************************************
  233. *                do_a_rest
  234. * Effect: parses a rest (R) command
  235. ****************************************************************************/
  236.  
  237. private void do_a_rest()
  238. {
  239.     if (fieldx < strlen(token))
  240.     fferror("Nothing expected after rest");
  241.     rest_flag = true;
  242. }
  243.  
  244. /****************************************************************************
  245. *                doabsdur
  246. * Effect: parses an absolute dur (U) command
  247. ****************************************************************************/
  248.  
  249. private void doabsdur()
  250. {
  251.     if (isdigit(token[fieldx])) {
  252.     dur = precise( (long) scanint());
  253.     dur = (dur * 100) / rate;
  254.     if (fieldx < strlen(token)) {
  255.         fieldx = 2;
  256.         fferror("U must be followed by digits only");
  257.     }
  258.     symbolic_dur_flag = false;
  259.     } else fferror("No digit after U");
  260. }
  261.  
  262. /****************************************************************************
  263. *                doabspitch
  264. * Effect: parses an absolute pitch (P) command
  265. ****************************************************************************/
  266.  
  267. private void doabspitch()
  268. {
  269.     if (isdigit (token[fieldx])) {
  270.     pitch = scanint();
  271.     pitch_flag = true;
  272.     if (fieldx < strlen(token))
  273.         fferror("P must be followed by digits only");
  274.     else if (pitch < minpitch) {
  275.         fieldx = 1;
  276.         fferror("Minimum pitch of 12 will be used");
  277.         pitch = minpitch;
  278.     } else if (pitch > maxpitch) {
  279.         fieldx = 1;
  280.         fferror("Maximum pitch of 115 will be used");
  281.         pitch = maxpitch;
  282.     }
  283.     } else fferror("No digits after P");
  284. }
  285.  
  286. /****************************************************************************
  287. *                docomment
  288. * Effect: parses a comment (*) command
  289. ****************************************************************************/
  290.  
  291. private void docomment()
  292. {
  293.     line[linex] = NULL; /* force end of line to skip comment line */
  294. }
  295.  
  296. /****************************************************************************
  297. *                doctrl
  298. * Inputs:
  299. *    n: control number
  300. * Effect: parses a control (J, K, M, O, X, or Y) command
  301. ****************************************************************************/
  302.  
  303. private void doctrl(n)
  304.     int n;
  305. {
  306.     ctrlval[n] = scanint();
  307.     if (fieldx < strlen(token) ) {
  308.     fferror("Only digits expected here");
  309.     } else {
  310.     ctrlflag[n] = true;
  311.     ctrlflag[0] = true;    /* ctrlflag[0] set if any flag is set */
  312.     }
  313. }
  314.  
  315. /****************************************************************************
  316. *                dodur
  317. * Effect: parses a duration (S, I, Q, H, or W) command
  318. ****************************************************************************/
  319.  
  320. private void dodur()
  321. {
  322.     int i, dotcnt = 0;
  323.     long dotfactor;
  324.  
  325.     for (i=0; i<=5; i++) {
  326.     if (durtable[i].symbol == token[fieldx-1]) {
  327.         dur = precise(durtable[i].value);
  328.         break;
  329.     }
  330.     }
  331.     if (i == 5) {
  332.     fieldx--;
  333.     fferror("Duration expected: one of W, H, Q, I, or S");
  334.     return;
  335.     }
  336.     while (fieldx < strlen(token)) {
  337.     if (token[fieldx] == 'T') {    /* triplet notation */
  338.         dur = (dur*2) / 3;
  339.         fieldx++;
  340.     } else if (token[fieldx] == '.') {    /* dotted notation */
  341.         dotcnt++;
  342.         fieldx++;
  343.     } else if (isdigit(token[fieldx])) {    /* numbers are multipliers */
  344.         dur = dur * (long) scanint();
  345.     } else {
  346.         fferror("Bad duration");
  347.         fieldx = strlen(token) + 1;
  348.     }
  349.     }
  350.     dotfactor = 1;
  351.     for (i=1; i<=dotcnt; i++)
  352.     dotfactor = dotfactor * 2;
  353.     dur = (2 * dur) - (dur / dotfactor);
  354.     dur = (dur * 100) / tempo;    /* time in centiseconds */
  355.     dur = (dur * 100) / rate;
  356.     symbolic_dur_flag = true;    /* see symbolic_dur_flag declaration */
  357. }
  358.  
  359. /****************************************************************************
  360. *                doerror
  361. * Effect: parse an unrecognized field by reporting an error
  362. ****************************************************************************/
  363.  
  364. private void doerror()
  365. {
  366.     fieldx = 0;
  367.     fferror("Bad field");
  368. }
  369.  
  370. /****************************************************************************
  371. *                doloud
  372. * Effect: parse a loudness (L) command
  373. ****************************************************************************/
  374.  
  375. private void doloud()
  376. {
  377.     int i, j;
  378.  
  379.     if (strlen(token) <= 1) {
  380.     fieldx = 0;
  381.     fferror("L must be followed by loudness indication");
  382.     return;
  383.     }
  384.     if (isdigit(token[fieldx])) {
  385.     loud = scanint();
  386.     if (fieldx < strlen(token))
  387.         fferror("Digits expected after L");
  388.     else if (loud > 127) {
  389.         fieldx = 1;
  390.         fferror("Maximum loudness of 127 will be used");
  391.         loud = 127;
  392.     }
  393.     return;
  394.     }
  395.     if (strlen(token) > 4 ) {    /* maximum is 4, e.g. "Lppp" */
  396.     fieldx = 0;
  397.     fferror("Loudness field too long");
  398.     return;
  399.     }
  400.     if (strlen(token) != 4) {    /* pad short symbols with 0    */
  401.     i = strlen(token);    /* e.g. "p\0" -> "p\0\0"    */
  402.     token[i+1] = '\0';
  403.     }
  404.     
  405.     for (i = 0; i <= 7; i++) {    /* loop through possibilities    */
  406.     for (j = 0; j <= 2; j++) {    /* test 3 characters    */
  407.         if (token[fieldx+j] != loudtable[i].symbol[j])
  408.         break;
  409.     }
  410.     if (j == 3) {
  411.         loud = loudtable[i].value;
  412.         return;
  413.     }
  414.     }
  415.     fieldx = 1;
  416.     fferror("Bad loudness indication");
  417. }
  418.  
  419. /****************************************************************************
  420. *                donextdur
  421. * Effect: parse a next (N) command
  422. * Implementation:
  423. *    The syntax is N followed by a duration, so save dur and use dodur()
  424. *    to parse the duration field.  Then restore dur (what a hack!).
  425. *    The form N<digits> is parsed directly with scanint().
  426. ****************************************************************************/
  427.  
  428. private void donextdur()
  429. {
  430.     long save;    /* save the current duration */
  431.     
  432.     ndurp = true;    /* flag that N was given */
  433.     if (isdigit(token[fieldx])) {
  434.     ntime = precise( (long) scanint());
  435.     if (fieldx < strlen(token))
  436.         fferror("Only digits were expected here");
  437.     } else {
  438.     fieldx++;
  439.     save = dur;    
  440.     dodur();
  441.     ntime = dur;    /* get the result from dur, */
  442.     dur = save;    /* and then restore it    */
  443.     }
  444. }
  445.  
  446. /****************************************************************************
  447. *                dopitch
  448. * Effect: parses a pitch command
  449. ****************************************************************************/
  450.  
  451. private void dopitch()
  452. {
  453.     int p, octave;
  454.     int octflag = false;    /* set if octave is specified */
  455.  
  456.     p = pitchtable[token[0]-'A'];
  457.     while (true) {
  458.     if (token[fieldx] == 'S') {                   /* sharp */
  459.         p++;
  460.         fieldx++;
  461.     } else if (token[fieldx] == 'N') {            /* skip */
  462.         fieldx++;
  463.     } else if (token[fieldx] == 'F') {            /* flat */
  464.         p--;
  465.         fieldx++;
  466.     } else if (isdigit(token[fieldx]) && !octflag) {      /* octave */
  467.         octave = scanint();
  468.         octflag = true;
  469.     } else break;                   /* none of the above */
  470.     }
  471.     if (octflag) p = (p-48) + 12 * octave;  /* adjust p to given octave */
  472.     else {          /* adjust p to note nearest the default pitch */
  473.     int octdiff = (p + 126 - pitch) / 12;
  474.     p = p + 120 - (octdiff * 12);
  475.     }
  476.     if (fieldx != strlen(token))        /* any unparsed characters? */
  477.     fferror("Bad pitch indication");
  478.     if (p > maxpitch) {                     /* pitch in range? */
  479.     fieldx = 1;
  480.     fferror("Pitch too high");
  481.     p = maxpitch;
  482.     }
  483.     pitch = p;
  484.     pitch_flag = true;
  485. }
  486.  
  487. /****************************************************************************
  488. *                doprogram
  489. * Effect: parses a program change (Z) command
  490. ****************************************************************************/
  491.  
  492. private void doprogram()
  493. {
  494.     if (isdigit(token[fieldx])) {
  495.     program = scanint();
  496.     if (fieldx < strlen(token)) {
  497.         fferror("Z must be followed by digits only");
  498.     } else if (program < minprogram) {
  499.         fieldx = 1;
  500.         fferror("Minimum program of 1 will be used");
  501.         program = minprogram;
  502.     } else if (program > maxprogram) {
  503.         fieldx = 1;
  504.         fferror("Maximum program of 128 will be used");
  505.         program = maxprogram;
  506.     }
  507.     } else fferror("No digit after Z");
  508. }
  509.  
  510. /****************************************************************************
  511. *                dorate
  512. * Effect: parses a !rate command
  513. ****************************************************************************/
  514.  
  515. private void dorate()
  516. {
  517.     linex += scan(&line[linex]);
  518.     if (strlen(token) == 0)
  519.     fferror("rate number expected");
  520.     else {
  521.     long oldrate = rate;
  522.     fieldx = 0;
  523.     rate = scanint();
  524.     if (fieldx < strlen(token) )
  525.         fferror("Only digits expected here");
  526.     if (rate == 0) {
  527.         fieldx = 0;
  528.         fferror("Rate 100 will be used here");
  529.         rate = 100;
  530.     }
  531.     start = thetime;
  532.     /* adjust dur in case it is inherited by next note */
  533.         dur = (dur * oldrate);
  534.         dur = dur / rate;
  535.     }
  536. }
  537.  
  538. /****************************************************************************
  539. *                dospecial
  540. * Effect: parses special (those starting with "!") commands
  541. ****************************************************************************/
  542.  
  543. private void dospecial()
  544. {
  545.     switch (issymbol()) {
  546.     case sym_tempo: dotempo();
  547.         break;
  548.     case sym_rate: dorate();
  549.         break;
  550.     default: fferror("Special command expected");
  551.     }
  552.     parseend(); /* flush the rest of the line */
  553. }
  554.  
  555. /****************************************************************************
  556. *                dotempo
  557. * Effect: parses a !tempo command
  558. ****************************************************************************/
  559.  
  560. private void dotempo()
  561. {
  562.     linex += scan(&line[linex]);
  563.     if (strlen(token) == 0)
  564.     fferror("Tempo number expected");
  565.     else {
  566.     long oldtempo = tempo;
  567.     fieldx = 0;
  568.     tempo = scanint();
  569.     if (fieldx < strlen(token))
  570.         fferror("Only digits expected here");
  571.     if (tempo == 0) {
  572.         fieldx = 0;
  573.         fferror("Tempo 100 will be used here");
  574.         tempo = 100;
  575.     }
  576.     start = thetime;
  577.     /* adjust dur in case it is inherited by next note */
  578.     if (symbolic_dur_flag) {
  579.         dur = (dur * oldtempo);
  580.         dur = dur / tempo;
  581.     }
  582.     }
  583. }
  584.  
  585. /****************************************************************************
  586. *                dotime
  587. * Effect: parses a time (T) command
  588. * Implementation: see implementation of donextdur()
  589. ****************************************************************************/
  590.  
  591. private void dotime()
  592. {
  593.     int save;
  594.  
  595.     if (isdigit(token[fieldx])) {
  596.     thetime = precise( (long) scanint());
  597.     if (fieldx < strlen(token) )
  598.         fferror("Only digits were expected here");
  599.     } else {
  600.         fieldx++;
  601.         save = dur; 
  602.         dodur(); 
  603.         thetime = dur;
  604.         dur = save;
  605.     }
  606.     thetime += start;    /* time is relative to start */
  607. }
  608.  
  609. /****************************************************************************
  610. *                dovoice
  611. * Effect: parse a voice (V) command (the voice is the MIDI channel)
  612. ****************************************************************************/
  613.  
  614. private void dovoice()
  615. {
  616.     if (isdigit(token[fieldx])) {
  617.     voice = scanint();
  618.     if (fieldx < strlen(token))
  619.         fferror("V must be followed by digits only");
  620.     if (voice > 16) {
  621.         fferror("number too high, using 16 instead");
  622.         voice = 16;
  623.     } else if (voice < 1) {
  624.         fferror("number too low, using 1 instead");
  625.         voice = 1;
  626.     }
  627.     } else fferror("No digit after V");
  628. }
  629.  
  630. /****************************************************************************
  631. *                fferror
  632. * Inputs:
  633. *    char *s: an error message string
  634. * Effect:
  635. *    prints the line with the error
  636. *    puts a cursor (^) at the error location
  637. *    prints the error message (s)
  638. * Implementation:
  639. *    this routine prints a carat under the character that
  640. *    was copied into token[fieldx].    E.g. if fieldx = 0, the
  641. *    carat will point to the first character in the field.
  642. ****************************************************************************/
  643.  
  644. private void fferror(s)
  645. char *s;
  646. {
  647.     fprintf(stderr, "%3d | ", lineno);
  648.     fprintf(stderr, "%s", line);
  649.     marker(linex-strlen(token)+fieldx+1+6);
  650.     fprintf(stderr, "Error: %s.\n", s);
  651. }
  652.  
  653. /****************************************************************************
  654. *                init
  655. * Outputs:    Returns true if OK, false on error.
  656. * Effect:    Initializes program state.
  657. ****************************************************************************/
  658.  
  659. private boolean init()
  660. {
  661.     int i;
  662.  
  663.     debug = cl_switch("-print");
  664.  
  665.     for (i = 0; i < nctrl; i++) ctrlflag[i] = false;
  666.  
  667.     dur = precise ((long) 60); /* quarter note */
  668.     lineno = 0;
  669.     thetime = 0;
  670.     pitch = 48;
  671.     loud = 127;
  672.     voice = 1;
  673.     last_prog = program = 1;
  674.     tempo = 100;
  675.     rate = 100;
  676.     start = 0;
  677.     symbolic_dur_flag = true; /*scale dur by tempo*/
  678.     return true;
  679. }
  680.  
  681. /****************************************************************************
  682. *                ins_ctrl
  683. * Inputs:
  684. *    event_type *score: a linked list in which to insert
  685. * Outputs:
  686. *    returns true on success, false on error (not enough space)
  687. * Effect: 
  688. *    control events corresponding to current line are inserted in score
  689. * Implementation:
  690. *    ctrlflag[i] is true if control i was specified in this line, so
  691. *    insert one control change for each ctrlflag[i] that is true
  692. ****************************************************************************/
  693.  
  694. private boolean ins_ctrl(score)
  695.     event_type *score;
  696. {
  697.     int i;
  698.     event_type ctrl;
  699.  
  700.     for (i = 1; i < nctrl; i++) {
  701.     if (ctrlflag[i]) {
  702.         ctrlflag[i] = false;
  703.         if ((ctrl = ctrlalloc()) == NULL) {
  704.         return false;
  705.         }
  706.         ctrl->ntime = round(thetime);
  707.         ctrl->nvoice = ctrl_voice(i, voice-1);
  708.         ctrl->nline = lineno;
  709.         ctrl->next = NULL;
  710.         ctrl->u.ctrl.value = ctrlval[i];
  711.         ins_event(score, ctrl);
  712.         ctrl_count ++;
  713.     }
  714.     }
  715.     return true;
  716. }
  717.  
  718. /****************************************************************************
  719. *                ins_event
  720. * Inputs:
  721. *    event_type *p: a linked list in which to insert
  722. *    event_type event: the new event to insert
  723. * Effect: 
  724. *    inserts event into score in reverse time order (this makes inserts
  725. *    that are sequential in time go fast)
  726. ****************************************************************************/
  727.  
  728. private void ins_event(p, event)
  729.     event_type *p;    /* the score */
  730.     event_type event;    /* the new event to insert */
  731. {
  732.     event_type ptr = *p;
  733.     event_type prv;
  734.  
  735.     if (ptr == NULL || event->ntime >= ptr->ntime) {
  736.     event->next = ptr;    /* insert at head of list */
  737.     *p = event;
  738.     } else { /* list insert */
  739.     while (ptr != NULL && event->ntime < ptr->ntime) {
  740.         prv = ptr;
  741.         ptr = ptr->next;
  742.     }
  743.     prv->next = event;
  744.     event->next = ptr;
  745.     }
  746. }
  747.  
  748. /****************************************************************************
  749. *                ins_note
  750. * Inputs:
  751. *    event_type *score: a linked list in which to insert
  752. * Outputs:
  753. *    returns true on success, false on error (not enough space)
  754. * Effect:
  755. *    note event (if any) corresponding to current line are inserted in 
  756. *    score
  757. * Implementation:
  758. *    if a note on should occur after a note off and doesn't, and the
  759. *    two notes have the same pitch, then the note off can cancel the
  760. *    note on:
  761. *        |------------------| <- this cancels *
  762. *               this -> |-----------| 
  763. *    To make it unlikely that roundoff will cause this situation,
  764. *    dur is decreased by one half of a clock tick before rounding.
  765. *    Also, phase2 gives precedence to note-offs that are simultaneous
  766. *    with note-ons.
  767. ****************************************************************************/
  768.  
  769. private boolean ins_note(score)
  770.     event_type *score;
  771. {
  772.     event_type nalloc(), note;
  773.     if ((note = nalloc()) == NULL) {
  774.     return false;
  775.     }
  776.     note->ntime = round(thetime);
  777.     note->nvoice = voice - 1;
  778.     note->nline = lineno;
  779.     note->next = NULL;
  780.     if (rest_flag) note->u.note.npitch = NO_PITCH;    /* a rest */
  781.     else note->u.note.npitch = pitch;
  782.     note->u.note.ndur = round(dur - (unity/2));
  783.     note->u.note.nloud = loud;
  784.     note->u.note.nprogram = program;
  785.     if (debug)
  786.     printf("note: time %ld, dur %ld, pitch %d, voice %d, loudness %d\n",
  787.         note->ntime, note->u.note.ndur, note->u.note.npitch,
  788.         note->nvoice, note->u.note.nloud);
  789.     ins_event(score, note);
  790.     return true;
  791. }
  792.  
  793. /****************************************************************************
  794. *                issymbol
  795. * Outputs: returns symbol number, or -1 if no match
  796. * Assumes: token[1] has the symbol to look up (token[0] == '!')
  797. ****************************************************************************/
  798.  
  799. private int issymbol()
  800. {
  801.     int i, symb_num;
  802.     char *sym;
  803.  
  804.     for (symb_num = 0; symb_num < sym_n; symb_num++) {
  805.     sym = ssymbols[symb_num];
  806.     i = 1;
  807.     while (true) {
  808.         if (token[i] != *sym) break;
  809.         if (*sym == 0) return symb_num;
  810.         sym++; i++;
  811.     }
  812.     }
  813.     return -1;
  814. }
  815.  
  816. /****************************************************************************
  817. *                marker
  818. * Inputs:
  819. *    int count: the number of characters to indent
  820. * Effect: 
  821. *    prints a carat (^) at the position specified on file stderr
  822. ****************************************************************************/
  823.  
  824. private void marker(count)
  825. int count;
  826. {
  827.     int i;
  828.     for (i=1; i<=count-1; i++)
  829.     fprintf (stderr, " ");
  830.     fprintf (stderr, "^\n");
  831. }
  832.  
  833. /****************************************************************************
  834. *                nalloc
  835. * Outputs: returns event_type for an event allocated from heap, NULL on error
  836. * Effect: allocates memory, decreases space accordingly
  837. ****************************************************************************/
  838.  
  839. private event_type nalloc()
  840. {    
  841.     char *getmem();
  842.     event_type result;
  843.     space -= sizeof(struct event_struct);
  844.     if (space > 0) {
  845.     result = ((event_type ) getmem (sizeof(struct event_struct)));
  846.     if (result == NULL)
  847.         printf("Internal error: Out of memory, space = %ld.\n",space);
  848.     } else result = NULL;
  849.     return result;
  850. }
  851.  
  852. /*****************************************************************
  853. *            parseend
  854. * Effect:
  855. *    parse the note terminator, either ",", ";", or "\n"
  856. *
  857. ****************************************************************/
  858.  
  859. private void parseend()
  860. {
  861.     linex += scan1(&line[linex]);
  862.     switch (token[0]) {
  863.     case ',':
  864.         ndurp = true;    /* switch that next time was specified */
  865.         ntime = 0;
  866.         break;
  867.     case ';':
  868.     case '\n':
  869.         break;
  870.     default:
  871.         fferror("Internal error: illegal separator?");
  872.         break;
  873.     }
  874. }
  875.  
  876. /****************************************************************************
  877. *                parsefield
  878. * Effect: looks at first character of token and calls a parsing routine
  879. *
  880. ****************************************************************************/
  881.  
  882. private void parsefield()
  883. {
  884.     fieldx = 1;
  885.     switch (token[0]) {
  886.     case 'T' : dotime(); break;
  887.     case 'W': 
  888.     case 'H':
  889.     case 'Q':
  890.     case 'S':
  891.     case 'I': dodur()  ; break;
  892.     case 'R': do_a_rest(); break;
  893.     case 'A':
  894.     case 'B':
  895.     case 'C':
  896.     case 'D':
  897.     case 'E':
  898.     case 'F':
  899.     case 'G': dopitch(); break;
  900.     case 'P': doabspitch (); break;
  901.     case 'U': doabsdur(); break;
  902.     case 'L': doloud(); break;
  903.     case 'N': donextdur(); break;
  904.     case 'J': doctrl(1); break;
  905.     case 'K': doctrl(2); break;
  906.     case 'M': doctrl(3); break;
  907.     case 'O': doctrl(4); break;
  908.     case 'X': doctrl(5); break;
  909.     case 'Y': doctrl(6); break;
  910.     case 'V': dovoice(); break;
  911.     case 'Z': doprogram(); break;
  912.     default : doerror(); break;
  913.     }
  914. }
  915.  
  916. /****************************************************************************
  917. *                parsenote
  918. * Inputs:
  919. *    event_type *scoreptr: pointer to the note list
  920. * Effect: 
  921. *    parses a note line -- control events (if any) and note event (if
  922. *    present) are inserted into *scoreptr
  923. * Assumes:
  924. *    line contains a string to be parsed
  925. ****************************************************************************/
  926.  
  927. private boolean parsenote(scoreptr)
  928.     event_type *scoreptr;    /* the translated note list */
  929. {
  930.     boolean out_of_memory = false;
  931.  
  932.     ndurp = false;
  933.     rest_flag = false;
  934.  
  935.     /* this loop reads tokens for a note */
  936.     while (strlen(token) > 0) {
  937.     parsefield();
  938.     linex += scan(&line[linex]);
  939.     }
  940.  
  941.     parseend(); /* take care of note terminator */
  942.  
  943.     /* insert a note if
  944.      *    (1) a pitch was specified OR
  945.      *    (2) no control was specified and this is not a rest 
  946.      *        (it's a pitch by default) OR
  947.      *    (3) there is a program change (even if this is a rest)
  948.      *
  949.      * NOTE: program changes during rests are advised since
  950.      *    synthesizers may not be able to process a program
  951.      *    change followed immediately by a note-on.  In fact, this
  952.      *    is why we insert notes whose pitch is NO_PITCH -- so that
  953.      *    the program change can be processed during the rest.
  954.      */
  955.     if (pitch_flag ||
  956.     (!ctrlflag[0] && !rest_flag) ||
  957.     (program != last_prog)) {
  958.     out_of_memory = !ins_note(scoreptr);
  959.     note_count ++;
  960.     }
  961.     /*
  962.      * insert ctrl's last so that when the score is reversed,
  963.      * they will be first.
  964.      */
  965.     if (ctrlflag[0]) {
  966.     out_of_memory |= !ins_ctrl(scoreptr);
  967.     ctrlflag[0] = false;
  968.     }
  969.     last_prog = program;
  970.  
  971.     if (ndurp) thetime += ntime;
  972.     else thetime += dur;
  973.  
  974.     return out_of_memory;
  975. }
  976.  
  977. /****************************************************************************
  978. *                phase1
  979. * Inputs:
  980. *    FILE *fp: input file
  981. * Outputs:
  982. *    returns event_type: the parsed score
  983. * Effect: 
  984. *    parses score from input file and builds score data structure
  985. ****************************************************************************/
  986.  
  987. event_type phase1(fp)
  988. FILE *fp;
  989. {
  990.     event_type score = NULL;    /* the translated note list */
  991.     boolean out_of_memory = false;    /* set when no more memory */
  992.  
  993.     if (!init()) {  /* something bad happened in init(), STOP */
  994.     fprintf(stderr,"WOOPS; something strange happened in INIT()!  ...exiting\n");
  995.     exit(1);
  996.     return NULL;    /* make lint happy */
  997.     }
  998.  
  999.     lineno = 0;
  1000.  
  1001.     /* this loop reads lines */
  1002.     while ((fgets(line, linesize, fp) != NULL) && !out_of_memory) {
  1003.     lineno++;
  1004.     linex = 0;
  1005.     /* this loop reads notes from a line */
  1006.     while ((line[linex] != NULL) && !out_of_memory) {
  1007.         /* loop invariant: line[linex] is first char of next note */
  1008.         pitch_flag = false;
  1009.         linex += scan(&line[linex]);
  1010.         if (!nullstring(token)) {
  1011.         if (token[0] == '*') docomment();
  1012.         else if (token[0] == '!') dospecial();
  1013.         else out_of_memory = parsenote(&score);
  1014.         } else parseend();
  1015.     }
  1016.     }
  1017.  
  1018.     fprintf (stderr,"\n");
  1019.  
  1020.     if (out_of_memory) {
  1021.     fprintf(stderr,"Out of note memory at line %d,\n", lineno-1);
  1022.     fprintf(stderr,"    the rest of your file will be ignored.\n");
  1023.     }
  1024.  
  1025.     printf (
  1026.     "\nPhase 1 completed; %d note(s), %d ctrl(s) have been translated.\n",
  1027.     note_count, ctrl_count);
  1028.  
  1029.     reverse(&score);
  1030.     return score;
  1031. }
  1032.  
  1033. /****************************************************************************
  1034. *                reverse
  1035. * Inputs:
  1036. *    event_type *p: pointer to a list of notes and control events
  1037. * Effect: reverses note and control events in p
  1038. ****************************************************************************/
  1039.  
  1040. private void reverse(p)
  1041. event_type *p;
  1042. {
  1043.     event_type p1, p2, p3;
  1044.     p1 = *p;
  1045.     if (p1 == NULL) return;
  1046.     p2 = p1->next;
  1047.     p1->next = NULL;
  1048.     while (p2 != NULL) {
  1049.     p3 = p2->next;
  1050.     p2->next = p1;
  1051.     p1 = p2;
  1052.     p2 = p3;
  1053.     }
  1054.     *p = p1;
  1055. }
  1056.  
  1057. /****************************************************************************
  1058. *                scan
  1059. * Inputs:
  1060. *    char *start: the string to scan
  1061. * Outputs:
  1062. *    returns int: the index of the next char in start to scan
  1063. * Effect: 
  1064. *    skips over leading blanks
  1065. *    copies characters from start into token, converting to upper case
  1066. *    scanning stops on delimiter: one of space, tab, newline, semicolon
  1067. ****************************************************************************/
  1068.  
  1069. private int scan(start)
  1070. char *start;
  1071. {
  1072.     int i = 0;
  1073.     int j = 0;
  1074.     char c;
  1075.  
  1076.     while (start[i] == ' ') i++;
  1077.  
  1078.     while ((c = start[i]) != ' ' && c != '\n' &&
  1079.        c != ',' && c != ';') {
  1080.     if (islower(start[i])) token[j] = toupper(start[i]);
  1081.     else token[j] = start[i];
  1082.     j++; i++;
  1083.     }
  1084.     token[j] = '\0';
  1085.     return i;
  1086. }
  1087.  
  1088. /****************************************************************************
  1089. *                scan1
  1090. * Inputs:
  1091. *    char *start: the string to scan
  1092. * Outputs:
  1093. *    returns int: the index of the next char in start to scan
  1094. * Effect: 
  1095. *    copies one char from start into token, converting to upper case
  1096. ****************************************************************************/
  1097.  
  1098. private int scan1(start)
  1099. char *start;
  1100. {
  1101.     int i = 0;
  1102.  
  1103.     token[0] = *start;
  1104.     if (islower(token[0])) token[0] = toupper(token[0]);
  1105.     
  1106.     if (!nullstring(token)) {
  1107.     token[1] = '\0';
  1108.     i = 1;
  1109.     }
  1110.     return i;
  1111. }
  1112.  
  1113. /****************************************************************************
  1114. *                scanint
  1115. * Outputs:
  1116. *    returns int: the scanned integer
  1117. * Effect:
  1118. *    scans an unsigned integer from token, starting at fieldx
  1119. *    fieldx is incremented to end of the integer
  1120. ****************************************************************************/
  1121.  
  1122. private int scanint()
  1123. {
  1124.     int i = 0;
  1125.     char c;
  1126.     while (fieldx < strlen(token)) {
  1127.     c = token[fieldx];
  1128.     if ((c >= '0') && (c<= '9')) {
  1129.         i = (i*10) + (c - '0');
  1130.         fieldx++;
  1131.     } else return i;
  1132.     }
  1133.     return i;
  1134. }
  1135.